home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
MOR55SRC.ZIP
/
MORIA
/
SOURCE
/
SAVE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-07
|
42KB
|
1,641 lines
/* source/save.c: save and restore games and monster memory info
Copyright (c) 1989-92 James E. Wilson, Robert A. Koeneke
This software may be copied and distributed for educational, research, and
not for profit purposes provided that this copyright and statement are
included in all such copies. */
/* For debugging the savefile code on systems with broken compilers. */
#if 0
#define DEBUG(x) x
#else
#define DEBUG(x)
#endif
#include <stdio.h>
#ifndef STDIO_LOADED
#define STDIO_LOADED
#endif
#ifdef __TURBOC__
#include <io.h>
#endif /* __TURBOC__ */
#include "config.h"
#include "constant.h"
#include "types.h"
#ifndef USG
/* stuff only needed for Berkeley UNIX */
#include <sys/types.h>
#include <sys/file.h>
#include <sys/param.h>
#endif
#ifdef VMS
#include <string.h>
#include <file.h>
#else
#ifdef USG
#ifndef ATARIST_MWC
#include <string.h>
#ifndef ATARIST_TC
#include <fcntl.h>
#endif
#else
#include "string.h"
#endif
#else
#include <strings.h>
#endif
#endif
/* This must be included after fcntl.h, which has a prototype for `open'
on some systems. Otherwise, the `open' prototype conflicts with the
`topen' declaration. */
#include "externs.h"
#ifdef ATARIST_TC
#include <time.h>
#endif
DEBUG(static FILE *logfile);
#if defined(LINT_ARGS)
static int sv_write(void);
static void wr_byte(int8u);
static void wr_short(int16u);
static void wr_long(int32u);
static void wr_bytes(int8u *, int);
static void wr_string(char *);
static void wr_shorts(int16u *, int);
static void wr_item(inven_type *);
static void wr_monster(monster_type *);
static void rd_byte(int8u *);
static void rd_short(int16u *);
static void rd_long(int32u *);
static void rd_bytes(int8u *, int);
static void rd_string(char *);
static void rd_shorts(int16u *, int);
static void rd_item(inven_type *);
static void rd_monster(monster_type *);
#else
static int sv_write();
static void wr_byte();
static void wr_short();
static void wr_long();
static void wr_bytes();
static void wr_string();
static void wr_shorts();
static void wr_item();
static void wr_monster();
static void rd_byte();
static void rd_short();
static void rd_long();
static void rd_bytes();
static void rd_string();
static void rd_shorts();
static void rd_item();
static void rd_monster();
#endif
#if !defined(ATARIST_MWC)
#ifdef MAC
#include <time.h>
#else
long time();
#endif
#else
char *malloc();
#endif
/* these are used for the save file, to avoid having to pass them to every
procedure */
static FILE *fileptr;
static int8u xor_byte;
static int from_savefile; /* can overwrite old savefile when save */
static int32u start_time; /* time that play started */
/* This save package was brought to by -JWT-
and -RAK-
and has been completely rewritten for UNIX by -JEW- */
/* and has been completely rewritten again by -CJS- */
/* and completely rewritten again! for portability by -JEW- */
static int sv_write()
{
int32u l;
register int i, j;
int count;
int8u char_tmp, prev_char;
register cave_type *c_ptr;
register recall_type *r_ptr;
struct stats *s_ptr;
register struct flags *f_ptr;
store_type *st_ptr;
struct misc *m_ptr;
#if defined(MSDOS) || defined(ATARI_ST)
inven_type *t_ptr;
#endif
/* clear the death flag when creating a HANGUP save file, so that player
can see tombstone when restart */
if (eof_flag)
death = FALSE;
l = 0;
if (find_cut)
l |= 0x1;
if (find_examine)
l |= 0x2;
if (find_prself)
l |= 0x4;
if (find_bound)
l |= 0x8;
if (prompt_carry_flag)
l |= 0x10;
if (rogue_like_commands)
l |= 0x20;
if (show_weight_flag)
l |= 0x40;
if (highlight_seams)
l |= 0x80;
if (find_ignore_doors)
l |= 0x100;
if (sound_beep_flag)
l |= 0x200;
if (display_counts)
l |= 0x400;
if (death)
l |= 0x80000000L; /* Sign bit */
if (total_winner)
l |= 0x40000000L;
for (i = 0; i < MAX_CREATURES; i++)
{
r_ptr = &c_recall[i];
if (r_ptr->r_cmove || r_ptr->r_cdefense || r_ptr->r_kills ||
r_ptr->r_spells || r_ptr->r_deaths || r_ptr->r_attacks[0] ||
r_ptr->r_attacks[1] || r_ptr->r_attacks[2] || r_ptr->r_attacks[3])
{
wr_short((int16u)i);
wr_long(r_ptr->r_cmove);
wr_long(r_ptr->r_spells);
wr_short(r_ptr->r_kills);
wr_short(r_ptr->r_deaths);
wr_short(r_ptr->r_cdefense);
wr_byte(r_ptr->r_wake);
wr_byte(r_ptr->r_ignore);
wr_bytes(r_ptr->r_attacks, MAX_MON_NATTACK);
}
}
wr_short((int16u)0xFFFF); /* sentinel to indicate no more monster info */
wr_long(l);
m_ptr = &py.misc;
wr_string(m_ptr->name);
wr_byte(m_ptr->male);
wr_long((int32u)m_ptr->au);
wr_long((int32u)m_ptr->max_exp);
wr_long((int32u)m_ptr->exp);
wr_short(m_ptr->exp_frac);
wr_short(m_ptr->age);
wr_short(m_ptr->ht);
wr_short(m_ptr->wt);
wr_short(m_ptr->lev);
wr_short(m_ptr->max_dlv);
wr_short((int16u)m_ptr->srh);
wr_short((int16u)m_ptr->fos);
wr_short((int16u)m_ptr->bth);
wr_short((int16u)m_ptr->bthb);
wr_short((int16u)m_ptr->mana);
wr_short((int16u)m_ptr->mhp);
wr_short((int16u)m_ptr->ptohit);
wr_short((int16u)m_ptr->ptodam);
wr_short((int16u)m_ptr->pac);
wr_short((int16u)m_ptr->ptoac);
wr_short((int16u)m_ptr->dis_th);
wr_short((int16u)m_ptr->dis_td);
wr_short((int16u)m_ptr->dis_ac);
wr_short((int16u)m_ptr->dis_tac);
wr_short((int16u)m_ptr->disarm);
wr_short((int16u)m_ptr->save);
wr_short((int16u)m_ptr->sc);
wr_short((int16u)m_ptr->stl);
wr_byte(m_ptr->pclass);
wr_byte(m_ptr->prace);
wr_byte(m_ptr->hitdie);
wr_byte(m_ptr->expfact);
wr_short((int16u)m_ptr->cmana);
wr_short(m_ptr->cmana_frac);
wr_short((int16u)m_ptr->chp);
wr_short(m_ptr->chp_frac);
for (i = 0; i < 4; i++)
wr_string (m_ptr->history[i]);
s_ptr = &py.stats;
wr_bytes(s_ptr->max_stat, 6);
wr_bytes(s_ptr->cur_stat, 6);
wr_shorts((int16u *)s_ptr->mod_stat, 6);
wr_bytes(s_ptr->use_stat, 6);
f_ptr = &py.flags;
wr_long(f_ptr->status);
wr_short((int16u)f_ptr->rest);
wr_short((int16u)f_ptr->blind);
wr_short((int16u)f_ptr->paralysis);
wr_short((int16u)f_ptr->confused);
wr_short((int16u)f_ptr->food);
wr_short((int16u)f_ptr->food_digested);
wr_short((int16u)f_ptr->protection);
wr_short((int16u)f_ptr->speed);
wr_short((int16u)f_ptr->fast);
wr_short((int16u)f_ptr->slow);
wr_short((int16u)f_ptr->afraid);
wr_short((int16u)f_ptr->poisoned);
wr_short((int16u)f_ptr->image);
wr_short((int16u)f_ptr->protevil);
wr_short((int16u)f_ptr->invuln);
wr_short((int16u)f_ptr->hero);
wr_short((int16u)f_ptr->shero);
wr_short((int16u)f_ptr->blessed);
wr_short((int16u)f_ptr->resist_heat);
wr_short((int16u)f_ptr->resist_cold);
wr_short((int16u)f_ptr->detect_inv);
wr_short((int16u)f_ptr->word_recall);
wr_short((int16u)f_ptr->see_infra);
wr_short((int16u)f_ptr->tim_infra);
wr_byte(f_ptr->see_inv);
wr_byte(f_ptr->teleport);
wr_byte(f_ptr->free_act);
wr_byte(f_ptr->slow_digest);
wr_byte(f_ptr->aggravate);
wr_byte(f_ptr->fire_resist);
wr_byte(f_ptr->cold_resist);
wr_byte(f_ptr->acid_resist);
wr_byte(f_ptr->regenerate);
wr_byte(f_ptr->lght_resist);
wr_byte(f_ptr->ffall);
wr_byte(f_ptr->sustain_str);
wr_byte(f_ptr->sustain_int);
wr_byte(f_ptr->sustain_wis);
wr_byte(f_ptr->sustain_con);
wr_byte(f_ptr->sustain_dex);
wr_byte(f_ptr->sustain_chr);
wr_byte(f_ptr->confuse_monster);
wr_byte(f_ptr->new_spells);
wr_short((int16u)missile_ctr);
wr_long((int32u)turn);
wr_short((int16u)inven_ctr);
for (i = 0; i < inven_ctr; i++)
wr_item(&inventory[i]);
for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++)
wr_item(&inventory[i]);
wr_short((int16u)inven_weight);
wr_short((int16u)equip_ctr);
wr_long(spell_learned);
wr_long(spell_worked);
wr_long(spell_forgotten);
wr_bytes(spell_order, 32);
wr_bytes(object_ident, OBJECT_IDENT_SIZE);
wr_long(randes_seed);
wr_long(town_seed);
wr_short((int16u)last_msg);
for (i = 0; i < MAX_SAVE_MSG; i++)
wr_string(old_msg[i]);
/* this indicates 'cheating' if it is a one */
wr_short((int16u)panic_save);
wr_short((int16u)total_winner);
wr_short((int16u)noscore);
wr_shorts(player_hp, MAX_PLAYER_LEVEL);
for (i = 0; i < MAX_STORES; i++)
{
st_ptr = &store[i];
wr_long((int32u)st_ptr->store_open);
wr_short((int16u)st_ptr->insult_cur);
wr_byte(st_ptr->owner);
wr_byte(st_ptr->store_ctr);
wr_short(st_ptr->good_buy);
wr_short(st_ptr->bad_buy);
for (j = 0; j < st_ptr->store_ctr; j++)
{
wr_long((int32u)st_ptr->store_inven[j].scost);
wr_item(&st_ptr->store_inven[j].sitem);
}
}
/* save the current time in the savefile */
#ifdef MAC
l = time((time_t *)0);
#else
l = time((long *)0);
#endif
if (l < start_time)
{
/* someone is messing with the clock!, assume that we have been
playing for 1 day */
l = start_time + 86400L;
}
wr_long(l);
/* starting with 5.2, put died_from string in savefile */
wr_string(died_from);
/* starting with 5.2.2, put the max_score in the savefile */
l = total_points ();
wr_long (l);
/* starting with 5.2.2, put the birth_date in the savefile */
wr_long ((int32u) birth_date);
/* only level specific info follows, this allows characters to be
resurrected, the dungeon level info is not needed for a resurrection */
if (death)
{
if (ferror(fileptr) || fflush(fileptr) == EOF)
return FALSE;
return TRUE;
}
wr_short((int16u)dun_level);
wr_short((int16u)char_row);
wr_short((int16u)char_col);
wr_short((int16u)mon_tot_mult);
wr_short((int16u)cur_height);
wr_short((int16u)cur_width);
wr_short((int16u)max_panel_rows);
wr_short((int16u)max_panel_cols);
for (i = 0; i < MAX_HEIGHT; i++)
for (j = 0; j < MAX_WIDTH; j++)
{
c_ptr = &cave[i][j];
if (c_ptr->cptr != 0)
{
wr_byte((int8u)i);
wr_byte((int8u)j);
wr_byte(c_ptr->cptr);
}
}
wr_byte((int8u)0xFF); /* marks end of cptr info */
for (i = 0; i < MAX_HEIGHT; i++)
for (j = 0; j < MAX_WIDTH; j++)
{
c_ptr = &cave[i][j];
if (c_ptr->tptr != 0)
{
wr_byte((int8u)i);
wr_byte((int8u)j);
wr_byte(c_ptr->tptr);
}
}
wr_byte((int8u)0xFF); /* marks end of tptr info */
/* must set counter to zero, note that code may write out two bytes
unnecessarily */
count = 0;
prev_char = 0;
for (i = 0; i < MAX_HEIGHT; i++)
for (j = 0; j < MAX_WIDTH; j++)
{
c_ptr = &cave[i][j];
char_tmp = c_ptr->fval | (c_ptr->lr << 4) | (c_ptr->fm << 5) |
(c_ptr->pl << 6) | (c_ptr->tl << 7);
if (char_tmp != prev_char || count == MAX_UCHAR)
{
wr_byte((int8u)count);
wr_byte(prev_char);
prev_char = char_tmp;
count = 1;
}
else
count++;
}
/* save last entry */
wr_byte((int8u)count);
wr_byte(prev_char);
#if defined(MSDOS) || defined(ATARI_ST)
/* must change graphics symbols for walls and floors back to default chars,
this is necessary so that if the user changes the graphics line, the
program will be able change all existing walls and floors to the new
symbol */
/* Or if the user moves the savefile from one machine to another, we
must have a consistent representation here. */
t_ptr = &t_list[tcptr - 1];
for (i = tcptr - 1; i >= MIN_TRIX; i--)
{
#ifdef MSDOS
if (t_ptr->tchar == wallsym)
t_ptr->tchar = '#';
#endif
#ifdef ATARI_ST
if (t_ptr->tchar == (unsigned char)240)
t_ptr->tchar = '#';
#endif
t_ptr--;
}
#endif
wr_short((int16u)tcptr);
for (i = MIN_TRIX; i < tcptr; i++)
wr_item(&t_list[i]);
wr_short((int16u)mfptr);
for (i = MIN_MONIX; i < mfptr; i++)
wr_monster(&m_list[i]);
if (ferror(fileptr) || (fflush(fileptr) == EOF))
return FALSE;
return TRUE;
}
#ifdef MAC
/* Set up prior to actual save, do the save, then clean up */
/* Notice that Mac version of this function takes a parameter */
/* To do a "save as" set always_ask */
/* To do a "save" clear always_ask */
int save_char(always_ask)
int always_ask;
{
int rc, already_set, proceed;
int16 vrefnum;
/* cannot rely on _save_char to do this because we may put up a dialog */
if (character_saved) return(TRUE);
enablefilemenu(FALSE);
already_set = getsavedefaults(savefile, &vrefnum);
if (!already_set || always_ask)
{
/* Here if always_ask or user has not yet specified a save file */
/* User specifies a save file when he restarts a previous one */
sfposition(vrefnum);
proceed = doputfile(death ? "Save memories as:" : "Save game as:",
savefile, &vrefnum);
}
else
proceed = TRUE;
if (proceed)
{
changedirectory(vrefnum);
rc = _save_char(savefile);
restoredirectory();
}
else
rc = FALSE;
if (rc)
(void) setfileinfo(savefile, vrefnum, SAVE_FTYPE);
enablefilemenu(TRUE);
return(rc);
}
#else
/* The Mac has different logic here -- See above */
int save_char()
{
int i;
vtype temp;
#ifdef SECURE
bePlayer();
#endif
while (!_save_char(savefile))
{
(void) sprintf(temp, "Savefile '%s' fails.", savefile);
msg_print(temp);
i = 0;
if (access(savefile, 0) < 0
|| get_check("File exists. Delete old savefile?") == 0
|| (i = unlink(savefile)) < 0)
{
if (i < 0)
{
(void) sprintf(temp, "Can't delete '%s'", savefile);
msg_print(temp);
}
prt("New Savefile [ESC to give up]:", 0, 0);
if (!get_string(temp, 0, 31, 45))
return FALSE;
if (temp[0])
(void) strcpy(savefile, temp);
}
(void) sprintf(temp, "Saving with %s...", savefile);
prt(temp, 0, 0);
}
#ifdef SECURE
beGames();
#endif
return TRUE;
}
#endif
int _save_char(fnam)
char *fnam;
{
vtype temp;
register int ok, fd;
int8u char_tmp;
if (character_saved)
return TRUE; /* Nothing to save. */
nosignals();
put_qio();
disturb (1, 0); /* Turn off resting and searching. */
change_speed(-pack_heavy); /* Fix the speed */
pack_heavy = 0;
ok = FALSE;
/* VMS files have version numbers, so don't worry about overwriting
the old save file. */
#if !defined(ATARIST_MWC) && !defined(VMS)
fd = -1;
fileptr = NULL; /* Do not assume it has been init'ed */
#if defined(MAC) || defined(AMIGA)
/* The Mac version automatically overwrites */
fd = open(fnam, O_RDWR|O_CREAT|O_TRUNC);
#ifdef MAC
macbeginwait ();
#endif
#else
fd = open(fnam, O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd < 0 && access(fnam, 0) >= 0 &&
(from_savefile ||
(wizard && get_check("Can't make new savefile. Overwrite old?"))))
{
(void) chmod(fnam, 0600);
fd = open(fnam, O_RDWR|O_TRUNC, 0600);
}
#endif
if (fd >= 0)
{
(void) close(fd);
#endif /* !ATARIST_MWC && !VMS */
/* GCC for atari st defines atarist */
#if defined(atarist) || defined(ATARI_ST) || defined(THINK_C) || defined(MSDOS)
fileptr = fopen(savefile, "wb");
#else
fileptr = fopen(savefile, "w");
#endif
#if !defined(ATARIST_MWC) && !defined(VMS)
}
#endif
DEBUG(logfile = fopen("IO_LOG", "a"));
DEBUG(fprintf (logfile, "Saving data to %s\n", savefile));
if (fileptr != NULL)
{
xor_byte = 0;
wr_byte((int8u)CUR_VERSION_MAJ);
xor_byte = 0;
wr_byte((int8u)CUR_VERSION_MIN);
xor_byte = 0;
wr_byte((int8u)PATCH_LEVEL);
xor_byte = 0;
char_tmp = randint(256) - 1;
wr_byte(char_tmp);
/* Note that xor_byte is now equal to char_tmp */
ok = sv_write();
DEBUG(fclose (logfile));
if (fclose(fileptr) == EOF)
ok = FALSE;
}
#ifdef MAC
macendwait ();
#endif
if (!ok)
{
if (fd >= 0)
(void) unlink(fnam);
signals();
if (fd >= 0)
(void) sprintf(temp, "Error writing to file %s", fnam);
else
(void) sprintf(temp, "Can't create new file %s", fnam);
msg_print(temp);
return FALSE;
}
else
character_saved = 1;
turn = -1;
signals();
return TRUE;
}
#ifdef MAC
/* Wrapper to set the appropriate directory */
int get_char(generate)
int *generate;
{
int rc, exit_flag;
int16 vrefnum;
(void) getsavedefaults(savefile, &vrefnum);
changedirectory(vrefnum);
rc = _get_char(generate, &exit_flag);
restoredirectory();
if (exit_flag)
exit_game();
return(rc);
}
#endif
/* Certain checks are ommitted for the wizard. -CJS- */
#ifdef MAC
int _get_char(generate, exit_flag)
int *generate, *exit_flag;
#else
int get_char(generate)
int *generate;
#endif
{
register int i, j;
int fd, c, ok, total_count;
int32u l, age, time_saved;
vtype temp;
int16u int16u_tmp;
register cave_type *c_ptr;
register recall_type *r_ptr;
struct misc *m_ptr;
struct stats *s_ptr;
register struct flags *f_ptr;
store_type *st_ptr;
int8u char_tmp, ychar, xchar, count;
int8u version_maj, version_min, patch_level;
#if defined(MSDOS) || defined(ATARI_ST)
inven_type *t_ptr;
#endif
#ifdef MAC
*exit_flag = FALSE;
#endif
nosignals();
*generate = TRUE;
fd = -1;
#ifndef MAC
/* Not required for Mac, because the file name is obtained through a dialog.
There is no way for a non existnat file to be specified. -BS- */
if (access(savefile, 0) != 0)
{
signals();
msg_print("Savefile does not exist.");
return FALSE; /* Don't bother with messages here. File absent. */
}
#endif
clear_screen();
(void) sprintf(temp, "Savefile %s present. Attempting restore.", savefile);
put_buffer(temp, 23, 0);
if (turn >= 0)
msg_print("IMPOSSIBLE! Attempt to restore while still alive!");
/* Allow restoring a file belonging to someone else, if we can delete it. */
/* Hence first try to read without doing a chmod. */
#if defined(MAC) || defined(AMIGA)
else if ((fd = open(savefile, O_RDONLY)) < 0)
#else
#ifdef ATARI_ST
else if (FALSE)
#else
else if ((fd = open(savefile, O_RDONLY, 0)) < 0
&& (chmod(savefile, 0400) < 0 ||
(fd = open(savefile, O_RDONLY, 0)) < 0))
#endif
#endif
msg_print("Can't open file for reading.");
else
{
turn = -1;
ok = TRUE;
(void) close(fd);
/* GCC for atari st defines atarist */
#if defined(atarist) || defined(ATARI_ST) || defined(THINK_C) || defined(MSDOS)
fileptr = fopen(savefile, "rb");
#else
fileptr = fopen(savefile, "r");
#endif
if (fileptr == NULL)
goto error;
#ifdef MAC
macbeginwait ();
#endif
prt("Restoring Memory...", 0, 0);
put_qio();
DEBUG(logfile = fopen("IO_LOG", "a"));
DEBUG(fprintf (logfile, "Reading data from %s\n", savefile));
xor_byte = 0;
rd_byte(&version_maj);
xor_byte = 0;
rd_byte(&version_min);
xor_byte = 0;
rd_byte(&patch_level);
xor_byte = 0;
rd_byte(&xor_byte);
/* COMPAT support savefiles from 5.0.14 to 5.0.17 */
/* support savefiles from 5.1.0 to present */
if ((version_maj != CUR_VERSION_MAJ)
#if 0
/* As of version 5.4, accept savefiles even if they have higher
version numbers. The savefile format was frozen as of version
5.2.2. */
|| (version_min > CUR_VERSION_MIN)
|| (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL)
#endif
|| (version_min == 0 && patch_level < 14))
{
prt("Sorry. This savefile is from a different version of umoria.",
2, 0);
goto error;
}
rd_short(&int16u_tmp);
while (int16u_tmp != 0xFFFF)
{
if (int16u_tmp >= MAX_CREATURES)
goto error;
r_ptr = &c_recall[int16u_tmp];
rd_long(&r_ptr->r_cmove);
rd_long(&r_ptr->r_spells);
rd_short(&r_ptr->r_kills);
rd_short(&r_ptr->r_deaths);
rd_short(&r_ptr->r_cdefense);
rd_byte(&r_ptr->r_wake);
rd_byte(&r_ptr->r_ignore);
rd_bytes(r_ptr->r_attacks, MAX_MON_NATTACK);
rd_short(&int16u_tmp);
}
/* for save files before 5.2.2, read and ignore log_index (sic) */
if ((version_min < 2) || (version_min == 2 && patch_level < 2))
rd_short(&int16u_tmp);
rd_long(&l);
if (l & 0x1)
find_cut = TRUE;
else
find_cut = FALSE;
if (l & 0x2)
find_examine = TRUE;
else
find_examine = FALSE;
if (l & 0x4)
find_prself = TRUE;
else
find_prself = FALSE;
if (l & 0x8)
find_bound = TRUE;
else
find_bound = FALSE;
if (l & 0x10)
prompt_carry_flag = TRUE;
else
prompt_carry_flag = FALSE;
if (l & 0x20)
rogue_like_commands = TRUE;
else
rogue_like_commands = FALSE;
if (l & 0x40)
show_weight_flag = TRUE;
else
show_weight_flag = FALSE;
if (l & 0x80)
highlight_seams = TRUE;
else
highlight_seams = FALSE;
if (l & 0x100)
find_ignore_doors = TRUE;
else
find_ignore_doors = FALSE;
/* save files before 5.2.2 don't have sound_beep_flag, set it on
for compatibility */
if ((version_min < 2) || (version_min == 2 && patch_level < 2))
sound_beep_flag = TRUE;
else if (l & 0x200)
sound_beep_flag = TRUE;
else
sound_beep_flag = FALSE;
/* save files before 5.2.2 don't have display_counts, set it on
for compatibility */
if ((version_min < 2) || (version_min == 2 && patch_level < 2))
display_counts = TRUE;
else if (l & 0x400)
display_counts = TRUE;
else
display_counts = FALSE;
/* Don't allow resurrection of total_winner characters. It causes
problems because the character level is out of the allowed range. */
if (to_be_wizard && (l & 0x40000000L))
{
msg_print ("Sorry, this character is retired from moria.");
msg_print ("You can not resurrect a retired character.");
}
else if (to_be_wizard && (l & 0x80000000L)
&& get_check("Resurrect a dead character?"))
l &= ~0x80000000L;
if ((l & 0x80000000L) == 0)
{
m_ptr = &py.misc;
rd_string(m_ptr->name);
rd_byte(&m_ptr->male);
rd_long((int32u *)&m_ptr->au);
rd_long((int32u *)&m_ptr->max_exp);
rd_long((int32u *)&m_ptr->exp);
rd_short(&m_ptr->exp_frac);
rd_short(&m_ptr->age);
rd_short(&m_ptr->ht);
rd_short(&m_ptr->wt);
rd_short(&m_ptr->lev);
rd_short(&m_ptr->max_dlv);
rd_short((int16u *)&m_ptr->srh);
rd_short((int16u *)&m_ptr->fos);
rd_short((int16u *)&m_ptr->bth);
rd_short((int16u *)&m_ptr->bthb);
rd_short((int16u *)&m_ptr->mana);
rd_short((int16u *)&m_ptr->mhp);
rd_short((int16u *)&m_ptr->ptohit);
rd_short((int16u *)&m_ptr->ptodam);
rd_short((int16u *)&m_ptr->pac);
rd_short((int16u *)&m_ptr->ptoac);
rd_short((int16u *)&m_ptr->dis_th);
rd_short((int16u *)&m_ptr->dis_td);
rd_short((int16u *)&m_ptr->dis_ac);
rd_short((int16u *)&m_ptr->dis_tac);
rd_short((int16u *)&m_ptr->disarm);
rd_short((int16u *)&m_ptr->save);
rd_short((int16u *)&m_ptr->sc);
rd_short((int16u *)&m_ptr->stl);
rd_byte(&m_ptr->pclass);
rd_byte(&m_ptr->prace);
rd_byte(&m_ptr->hitdie);
rd_byte(&m_ptr->expfact);
rd_short((int16u *)&m_ptr->cmana);
rd_short(&m_ptr->cmana_frac);
rd_short((int16u *)&m_ptr->chp);
rd_short(&m_ptr->chp_frac);
for (i = 0; i < 4; i++)
rd_string (m_ptr->history[i]);
s_ptr = &py.stats;
rd_bytes(s_ptr->max_stat, 6);
rd_bytes(s_ptr->cur_stat, 6);
rd_shorts((int16u *)s_ptr->mod_stat, 6);
rd_bytes(s_ptr->use_stat, 6);
f_ptr = &py.flags;
rd_long(&f_ptr->status);
rd_short((int16u *)&f_ptr->rest);
rd_short((int16u *)&f_ptr->blind);
rd_short((int16u *)&f_ptr->paralysis);
rd_short((int16u *)&f_ptr->confused);
rd_short((int16u *)&f_ptr->food);
rd_short((int16u *)&f_ptr->food_digested);
rd_short((int16u *)&f_ptr->protection);
rd_short((int16u *)&f_ptr->speed);
rd_short((int16u *)&f_ptr->fast);
rd_short((int16u *)&f_ptr->slow);
rd_short((int16u *)&f_ptr->afraid);
rd_short((int16u *)&f_ptr->poisoned);
rd_short((int16u *)&f_ptr->image);
rd_short((int16u *)&f_ptr->protevil);
rd_short((int16u *)&f_ptr->invuln);
rd_short((int16u *)&f_ptr->hero);
rd_short((int16u *)&f_ptr->shero);
rd_short((int16u *)&f_ptr->blessed);
rd_short((int16u *)&f_ptr->resist_heat);
rd_short((int16u *)&f_ptr->resist_cold);
rd_short((int16u *)&f_ptr->detect_inv);
rd_short((int16u *)&f_ptr->word_recall);
rd_short((int16u *)&f_ptr->see_infra);
rd_short((int16u *)&f_ptr->tim_infra);
rd_byte(&f_ptr->see_inv);
rd_byte(&f_ptr->teleport);
rd_byte(&f_ptr->free_act);
rd_byte(&f_ptr->slow_digest);
rd_byte(&f_ptr->aggravate);
rd_byte(&f_ptr->fire_resist);
rd_byte(&f_ptr->cold_resist);
rd_byte(&f_ptr->acid_resist);
rd_byte(&f_ptr->regenerate);
rd_byte(&f_ptr->lght_resist);
rd_byte(&f_ptr->ffall);
rd_byte(&f_ptr->sustain_str);
rd_byte(&f_ptr->sustain_int);
rd_byte(&f_ptr->sustain_wis);
rd_byte(&f_ptr->sustain_con);
rd_byte(&f_ptr->sustain_dex);
rd_byte(&f_ptr->sustain_chr);
rd_byte(&f_ptr->confuse_monster);
rd_byte(&f_ptr->new_spells);
rd_short((int16u *)&missile_ctr);
rd_long((int32u *)&turn);
rd_short((int16u *)&inven_ctr);
if (inven_ctr > INVEN_WIELD)
goto error;
for (i = 0; i < inven_ctr; i++)
rd_item(&inventory[i]);
for (i = INVEN_WIELD; i < INVEN_ARRAY_SIZE; i++)
rd_item(&inventory[i]);
rd_short((int16u *)&inven_weight);
rd_short((int16u *)&equip_ctr);
rd_long(&spell_learned);
rd_long(&spell_worked);
rd_long(&spell_forgotten);
rd_bytes(spell_order, 32);
rd_bytes(object_ident, OBJECT_IDENT_SIZE);
rd_long(&randes_seed);
rd_long(&town_seed);
rd_short((int16u *)&last_msg);
for (i = 0; i < MAX_SAVE_MSG; i++)
rd_string(old_msg[i]);
rd_short((int16u *)&panic_save);
rd_short((int16u *)&total_winner);
rd_short((int16u *)&noscore);
rd_shorts(player_hp, MAX_PLAYER_LEVEL);
if ((version_min >= 2)
|| (version_min == 1 && patch_level >= 3))
for (i = 0; i < MAX_STORES; i++)
{
st_ptr = &store[i];
rd_long((int32u *)&st_ptr->store_open);
rd_short((int16u *)&st_ptr->insult_cur);
rd_byte(&st_ptr->owner);
rd_byte(&st_ptr->store_ctr);
rd_short(&st_ptr->good_buy);
rd_short(&st_ptr->bad_buy);
if (st_ptr->store_ctr > STORE_INVEN_MAX)
goto error;
for (j = 0; j < st_ptr->store_ctr; j++)
{
rd_long((int32u *)&st_ptr->store_inven[j].scost);
rd_item(&st_ptr->store_inven[j].sitem);
}
}
if ((version_min >= 2)
|| (version_min == 1 && patch_level >= 3))
rd_long(&time_saved);
if (version_min >= 2)
rd_string(died_from);
if ((version_min >= 3)
|| (version_min == 2 && patch_level >= 2))
rd_long ((int32u *)&max_score);
else
max_score = 0;
if ((version_min >= 3)
|| (version_min == 2 && patch_level >= 2))
rd_long ((int32u *)&birth_date);
else
#ifdef MAC
birth_date = time((time_t *)0);
#else
birth_date = time((long *)0);
#endif
}
if ((c = getc(fileptr)) == EOF || (l & 0x80000000L))
{
if ((l & 0x80000000L) == 0)
{
if (!to_be_wizard || turn < 0)
goto error;
prt("Attempting a resurrection!", 0, 0);
if (py.misc.chp < 0)
{
py.misc.chp = 0;
py.misc.chp_frac = 0;
}
/* don't let him starve to death immediately */
if (py.flags.food < 0)
py.flags.food = 0;
/* don't let him die of poison again immediately */
if (py.flags.poisoned > 1)
py.flags.poisoned = 1;
dun_level = 0; /* Resurrect on the town level. */
character_generated = 1;
/* set noscore to indicate a resurrection, and don't enter
wizard mode */
to_be_wizard = FALSE;
noscore |= 0x1;
}
else
{
/* Make sure that this message is seen, since it is a bit
more interesting than the other messages. */
msg_print("Restoring Memory of a departed spirit...");
turn = -1;
}
put_qio();
goto closefiles;
}
if (ungetc(c, fileptr) == EOF)
goto error;
prt("Restoring Character...", 0, 0);
put_qio();
/* only level specific info should follow, not present for dead
characters */
rd_short((int16u *)&dun_level);
rd_short((int16u *)&char_row);
rd_short((int16u *)&char_col);
rd_short((int16u *)&mon_tot_mult);
rd_short((int16u *)&cur_height);
rd_short((int16u *)&cur_width);
rd_short((int16u *)&max_panel_rows);
rd_short((int16u *)&max_panel_cols);
/* read in the creature ptr info */
rd_byte(&char_tmp);
while (char_tmp != 0xFF)
{
ychar = char_tmp;
rd_byte(&xchar);
rd_byte(&char_tmp);
if (xchar > MAX_WIDTH || ychar > MAX_HEIGHT)
goto error;
cave[ychar][xchar].cptr = char_tmp;
rd_byte(&char_tmp);
}
/* read in the treasure ptr info */
rd_byte(&char_tmp);
while (char_tmp != 0xFF)
{
ychar = char_tmp;
rd_byte(&xchar);
rd_byte(&char_tmp);
if (xchar > MAX_WIDTH || ychar > MAX_HEIGHT)
goto error;
cave[ychar][xchar].tptr = char_tmp;
rd_byte(&char_tmp);
}
/* read in the rest of the cave info */
c_ptr = &cave[0][0];
total_count = 0;
while (total_count != MAX_HEIGHT*MAX_WIDTH)
{
rd_byte(&count);
rd_byte(&char_tmp);
for (i = count; i > 0; i--)
{
#ifndef ATARIST_MWC
if (c_ptr >= &cave[MAX_HEIGHT][0])
goto error;
#endif
c_ptr->fval = char_tmp & 0xF;
c_ptr->lr = (char_tmp >> 4) & 0x1;
c_ptr->fm = (char_tmp >> 5) & 0x1;
c_ptr->pl = (char_tmp >> 6) & 0x1;
c_ptr->tl = (char_tmp >> 7) & 0x1;
c_ptr++;
}
total_count += count;
}
rd_short((int16u *)&tcptr);
if (tcptr > MAX_TALLOC)
goto error;
for (i = MIN_TRIX; i < tcptr; i++)
rd_item(&t_list[i]);
rd_short((int16u *)&mfptr);
if (mfptr > MAX_MALLOC)
goto error;
for (i = MIN_MONIX; i < mfptr; i++)
rd_monster(&m_list[i]);
#if defined(MSDOS) || defined(ATARI_ST)
/* change walls and floors to graphic symbols */
t_ptr = &t_list[tcptr - 1];
for (i = tcptr - 1; i >= MIN_TRIX; i--)
{
#ifdef MSDOS
if (t_ptr->tchar == '#')
t_ptr->tchar = wallsym;
#endif
#ifdef ATARI_ST
if (t_ptr->tchar == '#')
t_ptr->tchar = (unsigned char) 240;
#endif
t_ptr--;
}
#endif
*generate = FALSE; /* We have restored a cave - no need to generate. */
if ((version_min == 1 && patch_level < 3)
|| (version_min == 0))
for (i = 0; i < MAX_STORES; i++)
{
st_ptr = &store[i];
rd_long((int32u *)&st_ptr->store_open);
rd_short((int16u *)&st_ptr->insult_cur);
rd_byte(&st_ptr->owner);
rd_byte(&st_ptr->store_ctr);
rd_short(&st_ptr->good_buy);
rd_short(&st_ptr->bad_buy);
if (st_ptr->store_ctr > STORE_INVEN_MAX)
goto error;
for (j = 0; j < st_ptr->store_ctr; j++)
{
rd_long((int32u *)&st_ptr->store_inven[j].scost);
rd_item(&st_ptr->store_inven[j].sitem);
}
}
/* read the time that the file was saved */
if (version_min == 0 && patch_level < 16)
time_saved = 0; /* no time in file, clear to zero */
else if (version_min == 1 && patch_level < 3)
rd_long(&time_saved);
if (ferror(fileptr))
goto error;
if (turn < 0)
error:
ok = FALSE; /* Assume bad data. */
else
{
/* don't overwrite the killed by string if character is dead */
if (py.misc.chp >= 0)
(void) strcpy(died_from, "(alive and well)");
character_generated = 1;
}
closefiles:
DEBUG(fclose (logfile));
if (fileptr != NULL)
{
if (fclose(fileptr) < 0)
ok = FALSE;
}
if (fd >= 0)
(void) close(fd);
#ifdef MAC
macendwait ();
#endif
if (!ok)
msg_print("Error during reading of file.");
else
{
/* let the user overwrite the old savefile when save/quit */
from_savefile = 1;
signals();
if (panic_save == 1)
{
(void) sprintf(temp, "This game is from a panic save. \
Score will not be added to scoreboard.");
msg_print (temp);
}
else if ((!noscore & 0x04) && duplicate_character ())
{
(void) sprintf (temp, "This character is already on the \
scoreboard; it will not be scored again.");
msg_print (temp);
noscore |= 0x4;
}
if (turn >= 0)
{ /* Only if a full restoration. */
weapon_heavy = FALSE;
pack_heavy = 0;
check_strength();
/* rotate store inventory, depending on how old the save file */
/* is foreach day old (rounded up), call store_maint */
/* calculate age in seconds */
#ifdef MAC
start_time = time((time_t *)0);
#else
start_time = time((long *)0);
#endif
/* check for reasonable values of time here ... */
if (start_time < time_saved)
age = 0;
else
age = start_time - time_saved;
age = (age + 43200L) / 86400L; /* age in days */
if (age > 10) age = 10; /* in case savefile is very old */
for (i = 0; i < age; i++)
store_maint();
}
if (noscore)
msg_print("This save file cannot be used to get on the score board.");
if (version_maj != CUR_VERSION_MAJ
|| version_min != CUR_VERSION_MIN)
{
(void) sprintf(temp,
"Save file version %d.%d %s on game version %d.%d.",
version_maj, version_min,
version_min <= CUR_VERSION_MIN
? "accepted" : "risky" ,
CUR_VERSION_MAJ, CUR_VERSION_MIN);
msg_print(temp);
}
if (turn >= 0)
return TRUE;
else
return FALSE; /* Only restored options and monster memory. */
}
}
turn = -1;
prt("Please try again without that savefile.", 1, 0);
signals();
#ifdef MAC
*exit_flag = TRUE;
#else
exit_game();
#endif
return FALSE; /* not reached, unless on mac */
}
static void wr_byte(c)
int8u c;
{
xor_byte ^= c;
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, "BYTE: %02X = %d\n", (int) xor_byte, (int) c));
}
static void wr_short(s)
int16u s;
{
xor_byte ^= (s & 0xFF);
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, "SHORT: %02X", (int) xor_byte));
xor_byte ^= ((s >> 8) & 0xFF);
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, " %02X = %d\n", (int) xor_byte, (int) s));
}
static void wr_long(l)
register int32u l;
{
xor_byte ^= (l & 0xFF);
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, "LONG: %02X", (int) xor_byte));
xor_byte ^= ((l >> 8) & 0xFF);
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, " %02X", (int) xor_byte));
xor_byte ^= ((l >> 16) & 0xFF);
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, " %02X", (int) xor_byte));
xor_byte ^= ((l >> 24) & 0xFF);
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, " %02X = %ld\n", (int) xor_byte, (long) l));
}
static void wr_bytes(c, count)
int8u *c;
register int count;
{
register int i;
register int8u *ptr;
DEBUG(fprintf (logfile, "%d BYTES:", count));
ptr = c;
for (i = 0; i < count; i++)
{
xor_byte ^= *ptr++;
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, " %02X = %d", (int) xor_byte,
(int) (ptr[-1])));
}
DEBUG(fprintf (logfile, "\n"));
}
static void wr_string(str)
register char *str;
{
DEBUG(char *s = str);
DEBUG(fprintf (logfile, "STRING:"));
while (*str != '\0')
{
xor_byte ^= *str++;
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, " %02X", (int) xor_byte));
}
xor_byte ^= *str;
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, " %02X = \"%s\"\n", (int) xor_byte, s));
}
static void wr_shorts(s, count)
int16u *s;
register int count;
{
register int i;
register int16u *sptr;
DEBUG(fprintf (logfile, "%d SHORTS:", count));
sptr = s;
for (i = 0; i < count; i++)
{
xor_byte ^= (*sptr & 0xFF);
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, " %02X", (int) xor_byte));
xor_byte ^= ((*sptr++ >> 8) & 0xFF);
(void) putc((int)xor_byte, fileptr);
DEBUG(fprintf (logfile, " %02X = %d", (int) xor_byte, (int) sptr[-1]));
}
DEBUG(fprintf (logfile, "\n"));
}
static void wr_item(item)
register inven_type *item;
{
DEBUG(fprintf (logfile, "ITEM:\n"));
wr_short(item->index);
wr_byte(item->name2);
wr_string(item->inscrip);
wr_long(item->flags);
wr_byte(item->tval);
wr_byte(item->tchar);
wr_short((int16u)item->p1);
wr_long((int32u)item->cost);
wr_byte(item->subval);
wr_byte(item->number);
wr_short(item->weight);
wr_short((int16u)item->tohit);
wr_short((int16u)item->todam);
wr_short((int16u)item->ac);
wr_short((int16u)item->toac);
wr_bytes(item->damage, 2);
wr_byte(item->level);
wr_byte(item->ident);
}
static void wr_monster(mon)
register monster_type *mon;
{
DEBUG(fprintf (logfile, "MONSTER:\n"));
wr_short((int16u)mon->hp);
wr_short((int16u)mon->csleep);
wr_short((int16u)mon->cspeed);
wr_short(mon->mptr);
wr_byte(mon->fy);
wr_byte(mon->fx);
wr_byte(mon->cdis);
wr_byte(mon->ml);
wr_byte(mon->stunned);
wr_byte(mon->confused);
}
static void rd_byte(ptr)
int8u *ptr;
{
int8u c;
c = getc(fileptr) & 0xFF;
*ptr = c ^ xor_byte;
xor_byte = c;
DEBUG(fprintf (logfile, "BYTE: %02X = %d\n", (int) c, (int) *ptr));
}
static void rd_short(ptr)
int16u *ptr;
{
int8u c;
int16u s;
c = (getc(fileptr) & 0xFF);
s = c ^ xor_byte;
xor_byte = (getc(fileptr) & 0xFF);
s |= (int16u)(c ^ xor_byte) << 8;
*ptr = s;
DEBUG(fprintf (logfile, "SHORT: %02X %02X = %d\n", (int) c, (int) xor_byte,\
(int) s));
}
static void rd_long(ptr)
int32u *ptr;
{
register int32u l;
register int8u c;
c = (getc(fileptr) & 0xFF);
l = c ^ xor_byte;
xor_byte = (getc(fileptr) & 0xFF);
l |= (int32u)(c ^ xor_byte) << 8;
DEBUG(fprintf (logfile, "LONG: %02X %02X ", (int) c, (int) xor_byte));
c = (getc(fileptr) & 0xFF);
l |= (int32u)(c ^ xor_byte) << 16;
xor_byte = (getc(fileptr) & 0xFF);
l |= (int32u)(c ^ xor_byte) << 24;
*ptr = l;
DEBUG(fprintf (logfile, "%02X %02X = %ld\n", (int) c, (int) xor_byte,\
(long) l));
}
static void rd_bytes(ch_ptr, count)
int8u *ch_ptr;
register int count;
{
register int i;
register int8u *ptr;
register int8u c;
DEBUG(fprintf (logfile, "%d BYTES:", count));
ptr = ch_ptr;
for (i = 0; i < count; i++)
{
c = (getc(fileptr) & 0xFF);
*ptr++ = c ^ xor_byte;
xor_byte = c;
DEBUG(fprintf (logfile, " %02X = %d", (int) c, (int) ptr[-1]));
}
DEBUG(fprintf (logfile, "\n"));
}
static void rd_string(str)
char *str;
{
register int8u c;
DEBUG(char *s = str);
DEBUG(fprintf (logfile, "STRING: "));
do
{
c = (getc(fileptr) & 0xFF);
*str = c ^ xor_byte;
xor_byte = c;
DEBUG(fprintf (logfile, "%02X ", (int) c));
}
while (*str++ != '\0');
DEBUG(fprintf (logfile, "= \"%s\"\n", s));
}
static void rd_shorts(ptr, count)
int16u *ptr;
register int count;
{
register int i;
register int16u *sptr;
register int16u s;
int8u c;
DEBUG(fprintf (logfile, "%d SHORTS:", count));
sptr = ptr;
for (i = 0; i < count; i++)
{
c = (getc(fileptr) & 0xFF);
s = c ^ xor_byte;
xor_byte = (getc(fileptr) & 0xFF);
s |= (int16u)(c ^ xor_byte) << 8;
*sptr++ = s;
DEBUG(fprintf (logfile, " %02X %02X = %d", (int) c, (int) xor_byte,\
(int) s));
}
DEBUG(fprintf (logfile, "\n"));
}
static void rd_item(item)
register inven_type *item;
{
DEBUG(fprintf (logfile, "ITEM:\n"));
rd_short(&item->index);
rd_byte(&item->name2);
rd_string(item->inscrip);
rd_long(&item->flags);
rd_byte(&item->tval);
rd_byte(&item->tchar);
rd_short((int16u *)&item->p1);
rd_long((int32u *)&item->cost);
rd_byte(&item->subval);
rd_byte(&item->number);
rd_short(&item->weight);
rd_short((int16u *)&item->tohit);
rd_short((int16u *)&item->todam);
rd_short((int16u *)&item->ac);
rd_short((int16u *)&item->toac);
rd_bytes(item->damage, 2);
rd_byte(&item->level);
rd_byte(&item->ident);
}
static void rd_monster(mon)
register monster_type *mon;
{
DEBUG(fprintf (logfile, "MONSTER:\n"));
rd_short((int16u *)&mon->hp);
rd_short((int16u *)&mon->csleep);
rd_short((int16u *)&mon->cspeed);
rd_short(&mon->mptr);
rd_byte(&mon->fy);
rd_byte(&mon->fx);
rd_byte(&mon->cdis);
rd_byte(&mon->ml);
rd_byte(&mon->stunned);
rd_byte(&mon->confused);
}
/* functions called from death.c to implement the score file */
/* set the local fileptr to the scorefile fileptr */
void set_fileptr(file)
FILE *file;
{
fileptr = file;
}
void wr_highscore(score)
high_scores *score;
{
DEBUG(logfile = fopen ("IO_LOG", "a"));
DEBUG(fprintf (logfile, "Saving score:\n"));
/* Save the encryption byte for robustness. */
wr_byte(xor_byte);
wr_long((int32u) score->points);
wr_long((int32u) score->birth_date);
wr_short((int16u) score->uid);
wr_short((int16u) score->mhp);
wr_short((int16u) score->chp);
wr_byte(score->dun_level);
wr_byte(score->lev);
wr_byte(score->max_dlv);
wr_byte(score->sex);
wr_byte(score->race);
wr_byte(score->class);
wr_bytes((int8u *)score->name, PLAYER_NAME_SIZE);
wr_bytes((int8u *)score->died_from, 25);
DEBUG(fclose (logfile));
}
void rd_highscore(score)
high_scores *score;
{
DEBUG(logfile = fopen ("IO_LOG", "a"));
DEBUG(fprintf (logfile, "Reading score:\n"));
/* Read the encryption byte. */
rd_byte (&xor_byte);
rd_long((int32u *)&score->points);
rd_long((int32u *)&score->birth_date);
rd_short((int16u *)&score->uid);
rd_short((int16u *)&score->mhp);
rd_short((int16u *)&score->chp);
rd_byte(&score->dun_level);
rd_byte(&score->lev);
rd_byte(&score->max_dlv);
rd_byte(&score->sex);
rd_byte(&score->race);
rd_byte(&score->class);
rd_bytes((int8u *)score->name, PLAYER_NAME_SIZE);
rd_bytes((int8u *)score->died_from, 25);
DEBUG(fclose (logfile));
}